package cn.plugins.generator.utils

import cn.plugins.generator.datatype.MysqlDataType
import cn.plugins.generator.datatype.PostgresqlDataType
import cn.plugins.generator.entity.ColumnEntity
import cn.plugins.generator.entity.TableEntity
import cn.plugins.generator.generate.*
import freemarker.template.Configuration
import java.text.SimpleDateFormat
import java.util.*
import kotlin.collections.ArrayList
import freemarker.template.DefaultObjectWrapper


/**
 * 创建于 2020-01-08 18:16
 *
 * @author jiangyun
 * @类说明：代码生成工具类
 */
object FreemarkerGenerateCodeUtil {

    /**
     * 生成代码
     * @param dbType                数据类型(如：mysql、postgresql)
     * @param url                   数据库连接地址
     * @param databaseName          数据库名称
     * @param userName              用户名
     * @param password              密码
     * @param frameworkType         框架类型(mybatis或mybatisplus)
     * @param tablePrefex           表前缀
     * @param tableName             表名称，多个使用英文逗号隔开
     * @param projectPath           项目绝对路径
     * @param packageName           包名称
     * @param controller            控制器文件夹名称
     * @param service               业务层文件夹名称
     * @param mapper                dao层文件夹名称
     * @param entity                实体文件夹名称
     * @param xml                   dao层对应xml文件夹名称
     * @param languageType          语言类型，目前只支持java和kotlin
     * @param author                作者
     * @param company               所属公司
     * @param apiPrefix             接口前缀
     * @param
     * @param enableGenerateDoc     是否允许生成swagger doc
     */
    @Throws(Exception::class)
    fun generateCode(
        dbType: String,
        url: String,
        databaseName: String,
        userName: String,
        password: String,
        frameworkType: String,
        tablePrefex: String,
        tableName: String,
        projectPath: String,
        packageName: String,
        controller: String,
        service: String,
        mapper: String,
        entity: String,
        xml: String,
        languageType: String,
        author: String,
        company: String,
        apiPrefix: String,
        enableGenerateDoc: Boolean,
        enableGenVuePage: Boolean
    ) {
        val attrTypes: Map<String, String>? = when (dbType) {
            "mysql" -> MysqlDataType.getMysqlParamType(languageType)
            "postgresql" -> PostgresqlDataType.getPostgresqlParamType(languageType)
            else -> null
        }
        val fullAttrTypes: Map<String, String>? = when (dbType) {
            "mysql" -> MysqlDataType.getFullMysqlParamType(languageType)
            "postgresql" -> PostgresqlDataType.getFullPostgresqlParamType(languageType)
            else -> null
        }
        val tableNames: List<String> = tableName.split(",")
        if (tableNames.isNotEmpty()) {
            var tables: MutableList<TableEntity> = ArrayList()
            var table: TableEntity?
            tableNames.forEach {
                println("start generate table: ${it}")
                if (!it.isBlank()) {
                    // 获取表信息
                    table = when (dbType) {
                        "mysql" -> MysqlDatabaseUtil.getTableInfo(url, databaseName, userName, password, it)
                        "postgresql" -> PostgresqlDatabaseUtil.getTableInfo(url, userName, password, it)
                        else -> null
                    }
                    if (table != null && !table!!.tableName.isNullOrBlank()) {
                        table!!.className = it.let { UnderlineToCamelUtil.underlineToCamel(it, tablePrefex) } // 避免异常处理
                        table!!.createTime = SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())
                        table!!.author = author
                        table!!.company = company
                        tables.add(table!!)
                    } else {
                        println("get table $it error,can't generate this table code")
                    }
                }
            }

            var haveBigDecimal = false
            var haveDate = false
            var columns: MutableList<ColumnEntity>?
            var pkColumns: MutableList<ColumnEntity>?
            for (index in 0 until tables.size) {
                // 获取表列
                columns = when (dbType) {
                    "mysql" -> MysqlDatabaseUtil.findTableColumns(
                        url,
                        databaseName,
                        userName,
                        password,
                        tables[index].tableName!!
                    )
                    "postgresql" -> PostgresqlDatabaseUtil.findTableColumns(
                        url,
                        userName,
                        password,
                        tables[index].tableName!!
                    )
                    else -> null
                }

                // 初始化主键列数组
                pkColumns = mutableListOf()
                for (subIndex in 0 until columns!!.size) {// 处理一些值及默认数据
                    columns[subIndex].attrName =
                        UnderlineToCamelUtil.underlineToCamel(columns[subIndex].columnName!!, true)
                    columns[subIndex].upcaseAttrName =
                        UnderlineToCamelUtil.firstCharToUpcaseOrLowcase(columns[subIndex].attrName!!, false)
                    columns[subIndex].attrType = attrTypes!!.getOrDefault(columns[subIndex].dataType, "Object")
                    columns[subIndex].fullAttrType = fullAttrTypes!!.getOrDefault(
                        columns[subIndex].dataType,
                        if (languageType == "java") "java.lang.Object" else "Object"
                    )
                    if (columns[subIndex].attrType!! == "Date") {
                        haveDate = true
                    }
                    if (columns[subIndex].attrType!! == "BigDecimal") {
                        haveBigDecimal = true
                    }
                    columns[subIndex].required = columns[subIndex].isNullable == "NO"
                    if (columns[subIndex].attrType!! == "Date") {
                        columns[subIndex].example = SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())
                    } else if (columns[subIndex].attrType!! != "Date" && !columns[subIndex].columnDefault.isNullOrBlank()) {
                        columns[subIndex].example = columns[subIndex].columnDefault
                    } else {
                        if (columns[subIndex].attrType!! == "Time") {
                            columns[subIndex].attrType = "java.sql.Time"
                            columns[subIndex].example = SimpleDateFormat("HH:mm:ss").format(Date())
                        }
                        if (columns[subIndex].attrType!! == "com.alibaba.fastjson.JSONObject") {
                            columns[subIndex].example = "{\"username:\":\"test\",\"pswd\":\"51565665\"}"
                        }
                        if (columns[subIndex].attrType!! == "Integer") {
                            columns[subIndex].example = "1"
                        }
                        if (columns[subIndex].attrType!! == "Long") {
                            columns[subIndex].example = "1000000000"
                        }
                        if (columns[subIndex].attrType!! == "BigDecimal") {
                            columns[subIndex].example = "1500.5"
                        }
                        if (columns[subIndex].attrType!! == "Boolean") {
                            columns[subIndex].example = "true"
                        }
                        if (columns[subIndex].attrType!! == "Float") {
                            columns[subIndex].example = "12.5"
                        }
                        if (columns[subIndex].attrType!! == "Double") {
                            columns[subIndex].example = "12.55"
                        }
                        if (columns[subIndex].attrType!! == "String") {
                            columns[subIndex].example = "字符串数据"
                            if (columns[subIndex].columnType!!.contentEquals("blob")) {
                                columns[subIndex].example = "二进制内容，需定义转换类进行转换，本代码生产插件不负责转换处理！"
                            }
                            if (columns[subIndex].attrName!!.contains("valid")) {
                                columns[subIndex].example = "1"
                            }
                            if (columns[subIndex].attrName!!.contains("remark")) {
                                columns[subIndex].example = "这里填写备注信息..."
                            }
                            if (columns[subIndex].attrName!!.contains("createBy") || columns[subIndex].attrName!!.contains(
                                    "updateBy"
                                )
                            ) {
                                columns[subIndex].example = "88fadd7334a44a19a27e0c5082405853"
                            }
                            if (columns[subIndex].attrName!!.contains("phone") || columns[subIndex].attrName!!.contains(
                                    "Phone"
                                )
                            ) {
                                columns[subIndex].example = "18785265489"
                            }
                            if (columns[subIndex].attrName!!.contains("email") || columns[subIndex].attrName!!.contains(
                                    "Email"
                                )
                            ) {
                                columns[subIndex].example = "test123456@163.com"
                            }
                            if (columns[subIndex].attrName!!.contains("userName") || columns[subIndex].attrName!!.contains(
                                    "UserName"
                                )
                            ) {
                                columns[subIndex].example = "张三"
                            }
                            if (columns[subIndex].attrName!!.contains("Name") || columns[subIndex].attrName!!.contains("name")) {
                                columns[subIndex].example = "名称"
                            }
                            if (columns[subIndex].attrName!!.contains("address") || columns[subIndex].attrName!!.contains(
                                    "Address"
                                )
                            ) {
                                columns[subIndex].example = "北京市丰台区丰台南路XX"
                            }
                            if (columns[subIndex].attrName!! == "password" || columns[subIndex].attrName!!.contains("Password") || columns[subIndex].attrName!!.contains(
                                    "pwd"
                                )
                            ) {
                                columns[subIndex].example = "08fbed7334444a19a27e0c5082405853"
                            }
                            if (!columns[subIndex].columnKey.isNullOrBlank() && columns[subIndex].columnKey == "PRI") {
                                columns[subIndex].example = "58fbed7334444a19a27e0c5082445658"
                                columns[subIndex].required = true
                                pkColumns.add(columns[subIndex])
                            }
                        }
                    }
                }
                tables[index].haveBigDecimal = haveBigDecimal
                tables[index].haveDate = haveDate
                tables[index].columns = columns
                tables[index].pkColumns = pkColumns
            }

            val config = Configuration(Configuration.VERSION_2_3_23)
            config.setClassLoaderForTemplateLoading(this@FreemarkerGenerateCodeUtil.javaClass.classLoader, "templates/")
            //config.setDirectoryForTemplateLoading(File("resources/templates/"))
            config.setEncoding(Locale.CHINA, "utf-8")
            config.objectWrapper = DefaultObjectWrapper()

            // 生成响应结果实体
            /*GenerateResponseEntity.freemarkerGenerate(
                frameworkType,
                config,
                projectPath,
                languageType,
                packageName,
                author,
                company,
                enableGenerateDoc
            )*/
            // 生成工具类
            /*GenerateJavaUtils.freemarkerGenerate(
                frameworkType,
                config,
                projectPath,
                languageType,
                packageName,
                author,
                company,
                enableGenerateDoc
            )*/

            var dataMap: MutableMap<String, Any?>
            tables.forEach {
                dataMap = mutableMapOf()
                dataMap["enableGenerateDoc"] = enableGenerateDoc
                dataMap["tableName"] = it.tableName
                dataMap["comment"] = it.comment
                dataMap["columns"] = it.columns
                dataMap["pkColumns"] = it.pkColumns
                dataMap["haveBigDecimal"] = it.haveBigDecimal
                dataMap["haveDate"] = it.haveDate
                dataMap["className"] = it.className!!.substring(0, 1).toUpperCase() + it.className!!.substring(1, it.className!!.length)
                dataMap["createTime"] = it.createTime
                dataMap["author"] = it.author
                dataMap["company"] = it.company
                dataMap["basePackage"] = packageName
                dataMap["controller"] = controller
                dataMap["service"] = service
                dataMap["mapper"] = mapper
                dataMap["entity"] = entity
                dataMap["apiPrefix"] = apiPrefix

                // 生成实体
                GenerateEntity.freemarkerGenerate(
                    frameworkType,
                    config,
                    projectPath,
                    packageName,
                    entity,
                    languageType,
                    it,
                    dataMap
                )
                // 生成新增pojo
                GenerateAddPOJO.freemarkerGenerate(
                    frameworkType,
                    config,
                    projectPath,
                    packageName,
                    entity,
                    languageType,
                    it,
                    dataMap
                )
                // 生成更新pojo
                GenerateUpdatePOJO.freemarkerGenerate(
                    frameworkType,
                    config,
                    projectPath,
                    packageName,
                    entity,
                    languageType,
                    it,
                    dataMap
                )
                // 生成vo
                GenerateVO.freemarkerGenerate(
                    frameworkType,
                    config,
                    projectPath,
                    packageName,
                    entity,
                    languageType,
                    it,
                    dataMap
                )
                // 生成mapper
                GenerateMapper.freemarkerGenerate(
                    frameworkType,
                    config,
                    projectPath,
                    packageName,
                    mapper,
                    languageType,
                    it,
                    dataMap
                )
                // 生成mapperXml
                GenerateMapperXml.freemarkerGenerate(
                    frameworkType,
                    config,
                    projectPath,
                    xml,
                    languageType,
                    it,
                    dataMap
                )
                // 生成service
                GenerateService.freemarkerGenerate(
                    frameworkType,
                    config,
                    projectPath,
                    packageName,
                    service,
                    languageType,
                    it,
                    dataMap
                )
                // 生成controller
                GenerateController.freemarkerGenerate(
                    frameworkType,
                    config,
                    projectPath,
                    packageName,
                    controller,
                    languageType,
                    it,
                    dataMap
                )
                // 生成vue页面
                if (enableGenVuePage) {
                    GenerateVuePage.freemarkerGenerate(
                        config,
                        projectPath,
                        it,
                        dataMap
                    )
                }
            }
            println(
                "   _____                           _          _____          _         _____                               _ \n" +
                        "  / ____|                         | |        / ____|        | |       / ____|                             | |\n" +
                        " | |  __  ___ _ __   ___ _ __ __ _| |_ ___  | |     ___   __| | ___  | (___  _   _  ___ ___ ___  ___ ___  | |\n" +
                        " | | |_ |/ _ \\ '_ \\ / _ \\ '__/ _` | __/ _ \\ | |    / _ \\ / _` |/ _ \\  \\___ \\| | | |/ __/ __/ _ \\/ __/ __| | |\n" +
                        " | |__| |  __/ | | |  __/ | | (_| | ||  __/ | |___| (_) | (_| |  __/  ____) | |_| | (_| (_|  __/\\__ \\__ \\ |_|\n" +
                        "  \\_____|\\___|_| |_|\\___|_|  \\__,_|\\__\\___|  \\_____\\___/ \\__,_|\\___| |_____/ \\__,_|\\___\\___\\___||___/___/ (_)\n" +
                        "                                                                                                             \n" +
                        "                                                                                                             "
            )
        } else {
            println("unavailable table or table not exists or running failure")
        }
    }
}